package org.lyfeng.spring.aop.support;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.lyfeng.spring.aop.annotation.After;
import org.lyfeng.spring.aop.annotation.Aspect;
import org.lyfeng.spring.aop.annotation.Before;
/**
 * jdk代理
 * @author leiyufeng
 * 2013-04-26 上午9:02:16
 */
public class JDKProxy implements AopProxy ,InvocationHandler{
	/**代理的方法列表**/
	private final Set</*Method*/String> methodCache=new LinkedHashSet<String>();
	
	private Object target;	
	private Object aspect;
	public JDKProxy(Object target,Object aspect)
	{
		this.target=target;
		this.aspect=aspect;
		Class<?> aspectClass=aspect.getClass();
		Aspect aspectAnnotation=aspectClass.getAnnotation(Aspect.class);
		String methodRegular=aspectAnnotation.method();
		resolveMethodRegular(methodRegular);
	}
	
	private void resolveMethodRegular(String methodRegular)
	{
		if("*".equals(methodRegular.trim()))
		{
			methodRegular="\\"+methodRegular;
		}
		Pattern pattern=Pattern.compile(methodRegular);
		Method[] methods=this.target.getClass().getDeclaredMethods();
		for(Method m:methods)
		{
			if (Modifier.isPublic(m.getModifiers())&&!Modifier.isStatic(m.getModifiers())) {
				//只代理public的非静态方法
				Matcher matcher = pattern.matcher(m.getName());
				if (matcher.matches()) {
					methodCache.add(m.getName());
				}
			}
		}
	}
	@Override
	public Object getProxy() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object getProxy(ClassLoader classLoader) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		// TODO Auto-generated method stub
		Object ret=null;
		if(!methodCache.contains(method.getName()))
		{
			ret=method.invoke(this.target,args);
			return ret;
		}
		Method[] methods=aspect.getClass().getDeclaredMethods();
		List<Method> beforeMethod=new ArrayList<Method>(10);
		List<Method> afterMethod=new ArrayList<Method>(10);
		for(Method m:methods)
		{
			if(null!=m.getAnnotation(Before.class))
			{
				beforeMethod.add(m);
			}
			if(null!=m.getAnnotation(After.class))
			{
				afterMethod.add(m);
			}
		}
		executeMethodList(aspect, beforeMethod);
		ret=method.invoke(this.target, args);
		executeMethodList(aspect, afterMethod);
		return ret;
	}
	private void executeMethodList(Object o,List<Method> methodList) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
	{
		for(Method m:methodList)
		{
			m.invoke(o, (Object[])null);
		}
	}
	
}
